﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#pragma once

#include <QDialog>
#include "OwnerPtr.h"
#include <list>
#include "ElementId.h"
#include "QListWidget"
#include "QTableWidget"
#include "NumberValidator.h"
#include "LineEditValidateHelper.h"
#include "ValidatorBase.h"

namespace Ui {
    class StoreyManagementDlg;
}

namespace gcmp
{
    class IDocument;
}

struct StoreyStruct
{
    StoreyStruct(const std::wstring& storeyName, double height, gcmp::ElementId id)
        : name(storeyName)
        , storeyHeight(height)
        , levelId(id)
    {}

    std::wstring name;
    double storeyHeight;
    gcmp::ElementId levelId;
};

class StoreyList
{
public:
    void AddStorey(const std::wstring& name, double elevation, gcmp::ElementId levelId);
    void AddStoreyAbove(const std::wstring& name, double storeyHeight, const std::wstring& preName);
    void AddStoreyBelow(const std::wstring& name, double storeyHeight, const std::wstring& postName);
    void RemoveStorey(const std::wstring& name);
    const std::list<StoreyStruct>& GetStoryList() const { return m_storeyList; }
    std::list<StoreyStruct>& GetStoryListFW() { return m_storeyList; }
    std::set<std::wstring> GetStoreyNames() const;
    double GetStartElevation() const { return m_startElevation; }
    void SetStartElevation(double elevation) { m_startElevation = elevation; }
    int GetStoreyCount() const { return (int)m_storeyList.size(); }
    double GetElevation(const StoreyStruct& storey) const;
private:
    std::list<StoreyStruct> m_storeyList;
    double m_startElevation;
};

struct BuildingStruct
{
    BuildingStruct(const std::wstring& buildingName, gcmp::ElementId id)
        : name(buildingName)
        , buildingId(id)
    {}
    std::wstring name;
    gcmp::ElementId buildingId;
    StoreyList storeyList;
};

class StoreyManagementDlg : public QDialog
{
    Q_OBJECT

public:
    explicit StoreyManagementDlg(gcmp::IDocument* pDoc, QWidget *parent = 0);
    ~StoreyManagementDlg();

    const std::vector<BuildingStruct>&  GetBuildings() const { return m_buildingList; }
    const std::vector<gcmp::ElementId>& GetDeletedBuildings() const { return m_deletedBuildings; }
protected:

    void InitDialog();

private:
    void UpdateStoreyTable(const std::wstring& selectedStoreyName = L"");
    void UpdateBuildingList(const std::wstring& selectedBuildingName = L"");
    void UpdateStartIndexLineEdit(int index);
    void onMoveRequested(const QPoint& cursorPos, const QPoint& offset);
    std::wstring GetCurrentStoreyName() const;

    StoreyList& GetCurrentStoreyList();
    BuildingStruct& GetCurrentBuildingStruct();
    StoreyList& GetStoreyListByBuildingId(gcmp::ElementId buildingId);

    bool IsBuildingNameExisted(const std::wstring& name);
    bool IsLevelNameExisted(const std::wstring& name);
    void InitValidators();
    bool CheckAddStoreyInput();

    virtual void keyPressEvent(QKeyEvent* event) override;
private slots:
    void OKButtonPushed();
    void CancelButtonPushed();

    void OnAddStoreyAboveButtonPushed();
    void OnAddStoreyBelowButtonPushed();
    void OnDeleteStoreyButtonPushed();

    void OnAddBuildingButtonPushed();
    void OnDeleteBuildingButtonPushed();

    void OnBuildingListItemClicked(QListWidgetItem *pItem);

    void OnBuildingListItemChanged(QListWidgetItem* pItem);
    void OnStoreyTableItemChanged(QTableWidgetItem* pItem);
private:
    gcmp::OwnerPtr<Ui::StoreyManagementDlg> ui;
    gcmp::IDocument* m_pDoc;
    //StoreyList m_storyList;
    std::vector<BuildingStruct> m_buildingList;
    std::wstring m_currentBuildingName;
    std::vector<gcmp::ElementId> m_deletedBuildings;

    gcmp::OwnerPtr<gcmp::LineEditValidateHelper> m_opValidateHelper;
    std::unordered_map<const QLineEdit*, const gcmp::ValidatorBase*> m_validators;
    gcmp::NumberValidator<int> m_startIndexValidator; //轴间距验证器
    gcmp::NumberValidator<int> m_storeyNumValidator; //轴间距验证器
    gcmp::NumberValidator<double> m_heightValidator; //轴间距验证器
};



